﻿using System;
using System.ComponentModel.DataAnnotations;

namespace uTrade.Core
{
    public class UpperPeriod : Indicator
    {
        private DataSeries close;
        private Bar bar;
        private bool newbar = false;

        protected override void Init()
        {
            close = Input;
        }

        protected override void OnBarUpdate()
        {
            DateTime dtBegin = MinBar.DateTime.Date;
            switch (IntervalType)
            {
                case IntervalType.Sec:
                    dtBegin = MinBar.DateTime.Date.AddHours(MinBar.DateTime.Hour).AddMinutes(MinBar.DateTime.Minute).AddSeconds(MinBar.DateTime.Second / Interval * Interval);
                    break;

                case IntervalType.Min:
                    dtBegin = MinBar.DateTime.Date.AddHours(MinBar.DateTime.Hour).AddMinutes(MinBar.DateTime.Minute / Interval * Interval);
                    break;

                case IntervalType.Hour:
                    dtBegin = MinBar.DateTime.Date.AddHours(MinBar.DateTime.Hour / Interval * Interval);
                    break;

                case IntervalType.Day:
                    dtBegin = MinBar.DateTime.Date;
                    break;

                case IntervalType.Week:
                    //dtBegin = DateTime.ParseExact(MinBar.TradingDay.ToString(), "yyyyMMdd", null);
                    dtBegin = dtBegin.Date.AddDays(1 - (byte)dtBegin.DayOfWeek);
                    break;

                case IntervalType.Month:
                    //dtBegin = DateTime.ParseExact(MinBar.TradingDay.ToString(), "yyyyMMdd", null);
                    dtBegin = new DateTime(dtBegin.Year, dtBegin.Month, 1);
                    break;

                case IntervalType.Year:
                    //dtBegin = DateTime.ParseExact(MinBar.TradingDay.ToString(), "yyyyMMdd", null);
                    dtBegin = new DateTime(dtBegin.Year, 1, 1);
                    break;

                default:
                    throw new Exception("参数错误");
            }
            if (bar == null) //首次调用
            {
                bar = new Bar
                {
                    DateTime = dtBegin,
                    Volume = MinBar.Volume, // kOld.preVol == 0 ? 0 : _tick.Volume - kOld.preVol;
                };
                bar.High = MinBar.High;
                bar.Low = MinBar.Low;
                bar.Open = MinBar.Open;
                bar.Close = MinBar.Close;
                newbar = true;
            }
            else
            {
                if (bar.DateTime == dtBegin) //在当前K线范围内
                {
                    newbar = false;
                    bar.High = Math.Max(bar.High, MinBar.High);
                    bar.Low = Math.Min(bar.Low, MinBar.Low);
                    bar.Close = MinBar.Close;
                    bar.Volume = bar.Volume + MinBar.Volume;
                }
                else if (dtBegin > bar.DateTime)
                {
                    newbar = true;
                    bar.DateTime = dtBegin;
                    bar.Volume = MinBar.Volume;
                    bar.Open = MinBar.Open;
                    bar.High = MinBar.High;
                    bar.Low = MinBar.Low;
                    bar.Close = MinBar.Close;
                }
            }

            if (newbar)
            {
                Date.Add(double.Parse(bar.DateTime.ToString("yyyyMMdd")));
                Time.Add(double.Parse(bar.DateTime.ToString("0.HHmmss")));
                Open.Add(bar.Open);
                High.Add(bar.High);
                Low.Add(bar.Low);
                Close.Add(bar.Close);
                Volume.Add(bar.Volume);
            }
            else
            {
                High[0] = bar.High;
                Low[0] = bar.Low;
                Close[0] = bar.Close;
                Volume[0] = bar.Volume;
            }
        }

        public DataSeries Date { get; set; } = new DataSeries();
        public DataSeries Time { get; set; } = new DataSeries();
        public DataSeries Open { get; set; } = new DataSeries();
        public DataSeries High { get; set; } = new DataSeries();
        public DataSeries Low { get; set; } = new DataSeries();
        public DataSeries Close { get; set; } = new DataSeries();
        public DataSeries Volume { get; set; } = new DataSeries();

        #region Properties

        public Bar MinBar { get; set; }

        [Range(1, int.MaxValue)]
        [Parameter("Interval")]
        public int Interval { get; set; } = 5;

        [Range(1, int.MaxValue)]
        [Parameter("IntervalType")]
        public IntervalType IntervalType { get; set; } = IntervalType.Min;

        #endregion Properties
    }

    #region generated code. Neither change nor remove.

    public partial class Indicator
    {
        private UpperPeriod[] cacheUpperPeriod;

        public UpperPeriod UpperPeriod(DataSeries close, Bar curMinBar, int interval, IntervalType type)
        {
            if (cacheUpperPeriod != null)
                for (int idx = 0; idx < cacheUpperPeriod.Length; idx++)
                    if (cacheUpperPeriod[idx] != null && cacheUpperPeriod[idx].Interval == interval && cacheUpperPeriod[idx].IntervalType == type && cacheUpperPeriod[idx].EqualsInput(close))
                        return cacheUpperPeriod[idx];
            return CacheIndicator(new UpperPeriod() { Interval = interval, IntervalType = type, MinBar = curMinBar, Input = close }, ref cacheUpperPeriod);
        }
    }

    #endregion generated code. Neither change nor remove.

    public partial class Strategy
    {
        public UpperPeriod UpperPeriod(int inteval, IntervalType type)
        {
            return UpperPeriod(Datas[0], inteval, type);
        }

        public UpperPeriod UpperPeriod(TransDatas data, int inteval, IntervalType type)
        {
            return Indicator.UpperPeriod(data.Close, data.CurrentMinBar, inteval, type);
        }
    }
}